package io.kiki.stack.http.feign;

import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.WildcardType;
import java.util.concurrent.CompletableFuture;

class ReflectiveFeignTargetSpecificationVerifier {
    public static <T> void verify(Target<T> target) {
        Class<T> type = target.type();
        if (!type.isInterface()) {
            throw new IllegalArgumentException("Type must be an interface: " + type);
        }

        for (final Method method : type.getMethods()) {
            final Class<?> retType = method.getReturnType();

            if (!CompletableFuture.class.isAssignableFrom(retType)) {
                continue; // synchronous case
            }

            if (retType != CompletableFuture.class) {
                throw new IllegalArgumentException("Method return type is not CompleteableFuture: " + getFullMethodName(type, retType, method));
            }

            final Type genRetType = method.getGenericReturnType();

            if (!(genRetType instanceof ParameterizedType)) {
                throw new IllegalArgumentException("Method return type is not parameterized: " + getFullMethodName(type, genRetType, method));
            }

            if (((ParameterizedType) genRetType).getActualTypeArguments()[0] instanceof WildcardType) {
                throw new IllegalArgumentException("Wildcards are not supported for return-type parameters: " + getFullMethodName(type, genRetType, method));
            }
        }
    }

    private static String getFullMethodName(Class<?> type, Type retType, Method m) {
        return retType.getTypeName() + " " + type.toGenericString() + "." + m.getName();
    }
}
